﻿using Baidu.Api.Util;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;

namespace Baidu.Api
{
    public class DefaultBaiduClient : IBaiduClient
    {
        private const string SERVER_URL = "https://pcs.baidu.com/rest/2.0/";
        public const string ACCESS_TOKEN = "access_token";
        public const string METHOD = "method";

        /// <summary>
        /// 禁用响应结果解释
        /// </summary>
        public bool DisableParser { private get; set; }
        public string AccessToken { get; set; }
        public string ServerUrl { get; private set; }

        private WebUtils webUtils = new WebUtils();

        #region Constructors

        public DefaultBaiduClient(string access_token) : this(SERVER_URL, access_token) { }

        public DefaultBaiduClient(string serverUrl, string access_token)
        {
            this.ServerUrl = serverUrl;
            this.AccessToken = access_token;
        }

        #endregion

        #region IBaiduClient

        public T Execute<T>(IBaiduRequest<T> request) where T : BaiduResponse
        {
            return Execute(this.ServerUrl, request);
        }

        public T Execute<T>(string serverUrl, IBaiduRequest<T> request) where T : BaiduResponse
        {
            return Execute(serverUrl, request, this.AccessToken);
        }

        public T Execute<T>(string serverUrl, IBaiduRequest<T> request, string access_token) where T : BaiduResponse
        {
            try
            {
                request.Validate();
            }
            catch (BaiduException e)
            {
                return createErrorResponse<T>(e.ErrorCode, e.ErrorMsg);
            }

            // method 及 access token 等参数必须携带在 query_string 中进行传输
            IDictionary<string, string> txtParams = new Dictionary<string, string>();
            txtParams.Add(METHOD, request.GetMethod());
            txtParams.Add(ACCESS_TOKEN, access_token);

            string url = WebUtils.BuildGetUrl(serverUrl + request.GetObjectName(), txtParams);

            string body;

            if (request is IBaiduParamsRequest<T>)
            {
                // 特殊POST请求
                IBaiduParamsRequest<T> pRequest = (IBaiduParamsRequest<T>)request;
                url = WebUtils.BuildGetUrl(url, pRequest.GetQueryParameters());
                body = webUtils.DoPost(url, request.GetFormParameters());
            }
            else if (request is IBaiduUploadRequest<T>)
            {
                // 上传文件请求
                IBaiduUploadRequest<T> uRequest = (IBaiduUploadRequest<T>)request;
                IDictionary<string, FileItem> fileParams = uRequest.GetFileParameters();
                body = webUtils.DoPost(url, null, fileParams);
            }
            else
            {
                // 普通POST请求
                body = webUtils.DoPost(url, request.GetFormParameters());
            }

            // 解释响应结果
            T rsp;

            if (DisableParser)
            {
                rsp = Activator.CreateInstance<T>();
            }
            else
            {
                rsp = BaiduUtils.ParseResponse<T>(body);
            }

            if (rsp != null)
            {
                rsp.ReqUrl = url;
                rsp.Body = body;
            }

            return rsp;
        }

        #endregion

        #region download file

        const string DOWNLOAD_URL = "https://d.pcs.baidu.com/rest/2.0/pcs/file";

        public string DownloadUrlBuild(string path)
        {
            return DownloadUrlBuild(DOWNLOAD_URL, this.AccessToken, path);
        }

        public static string DownloadUrlBuild(string access_token, string path)
        {
            return DownloadUrlBuild(DOWNLOAD_URL, access_token, path);
        }

        public static string DownloadUrlBuild(string serverUrl, string access_token, string path)
        {
            var txtParams = new BaiduDictionary();
            txtParams.Add(METHOD, "download");
            txtParams.Add(ACCESS_TOKEN, access_token);
            txtParams.Add("path", path);
            return WebUtils.BuildGetUrl(serverUrl, txtParams);
        }

        #endregion

        private static T createErrorResponse<T>(int errCode, string errMsg) where T : BaiduResponse
        {
            T rsp = Activator.CreateInstance<T>();
            rsp.ErrorCode = errCode;
            rsp.ErrorMsg = errMsg;

            IDictionary<string, object> errObj = new Dictionary<string, object>();
            errObj.Add("request_id", 0);
            errObj.Add("error_code", errCode);
            errObj.Add("error_msg", errMsg);

            string body = JsonConvert.SerializeObject(errObj);
            rsp.Body = body;
            return rsp;
        }
    }
}
